Description
Access functions provide a mechanism for active objects to reference connections and the events that they retrieve. They are provided as a means of unsulating user code from changes in circuitry and are generated by the translator for use with both automatic and manual connections. The generated access functions are private to the active object elements that own them.
The general form of an access is;
AccessFn(...).MemberFn(...);
The AccessFn call returns a reference to a connection object and the MemberFn call performs some operation using the connection object. The following example writes to a transient store using a manual connection (see diagram below);
Aux1_CTst1Cxn().OpenWrite(); // Wait for write access
Aux1_CTst1Cxn().Record().Construct(); // Construct the store's record (data object)
Populate( Aux1_CTst1Cxn().Record().Data() ); // Populate the store's record
Aux1_CTst1Cxn().Close(); // Close the connection
If we now inserted a distributor between the method and store in the diagram below, and retranslated, the user code above would remain unaffected.
Access Function Naming
Default access function names are generated with the following scheme;
Root Name + "_" + Connection Name + "Cxn"
Root names are associated with the consuming active object and the default naming scheme is shown below. By default, manual connections are numbered from '1'.
Connection names are associated with the providing object and default names are generated using the scheme shown below. By default providing connections are also numbered from '1'.
Provider Name + "_" + Provider Type
In the example above the root name is "Aux1" (default for the first manual connection), the provider name is "C", and the provider type is "Tst". This therefore generates an access function with default name;
Aux1_CTst1Cxn
The default root names and connection names can be reset to any name if required.
Access Function Arguments
In the example above, the executing active object element is assumed to own a single connection object. In the general case however, executing elements may own arrays of connections.
In the example below a method with dimensionality [N] has a manual connection to a store with dimensionality [N][M]. This would mean that by default each of the 'N' elements of the method would have a manual connection array with dimensionality [M]. This means that each connection references one of the [M] store elements, and the connection attributes would be initialized to those specified in the store connection properties window. This is referred to as a 'mapped' connection (see Manual Connections).
In order for element 'n' of the method to write to element 'n,m' of the store, the method needs to reference the appropriate connection element. Since each method element owns 'M' connections, this needs to be specified in the generated access function. Once the connection is referenced however, its attributes are already set, and the member function call can be made using the overload that does not require any arguments. The following code will write to each for the 'M' elements that the method element is connected to;
Uns m;
for ( m = 0; m < M; m++ ){
Aux1_CTst1Cxn(m).OpenWrite(); // Wait for write access to the connected element
}
for ( m = 0; m < M; m++ ){
Aux1_CTst1Cxn(m).Record().Construct(); // Construct the store's record (data object)
Populate( Aux1_CTst1Cxn(m).Record().Data() ); // Populate the store's record
Aux1_CTst1Cxn(m).Close(); // Close the connection
}
In the example above, each method element owns [M] connections and each of these is 'mapped' to a different element of the connected store. The example below does not require more than one store element to be opened simultaneously and this allows a a more economic approach. This involves creating a single connection and re-using it to access each store element sequentially. This would require the following slightly revised code;
for (Uns m = 0; m < M; m++ ){
// Wait for write access to element m
Aux1_CTst1Cxn(m).OpenWrite( 0, // Key is not used, zero will do
CLP_WAIT ); // Block until write-able
Aux1_CTst1Cxn(m).Record().Construct(); // Construct the opened element's record
Populate( Aux1_CTst1Cxn(m).Record().Data() ); // Populate the record (assumes user 'Populate' call)
Aux1_CTst1Cxn(m).Close(); // Close the opened connection
}
By default the translator will generate code for the 'mapped' connection case (first of the two above), but this can be over-ridden by changing the connection dimensionality (Dimension attribute). In the second case above, the connection dimensionality has been changed from [M] to [1].
The main difference between the mapped and unmapped solutions above, is that in the mapped case the access function requires the element to be identified, whilst in the unmapped case, the 'OpenWrite' member function requires the element to be identified. In both cases however, a single argument is required, which reflects the fact that each element of the method maps to [M] elements of its providing store. In the second case, the element has been set by the 'OpenWrite' and so the remaining member functions calls ( Construct(), Record() and Close() ) do not require the element to be specified.
Access Function Return Types
The connection types returned by access functions are determined by the name of the connection to the ultimate provider object as follows:
"I" + Provider Connection Name + "Cxn"
E.g.
ITstInst1Tst1Cxn
Notes
In the example above, each element of the method is mapped to 'M' elements of the store. It is usually the case that the mapping can be determined by 'cancelling' shared dimensions as is the case with this example. So if the consumer had dimensionality [L] and the provider had dimensionality [L][N][M] then each consumer element would map to [N][M] elements of the provider. If the consumer had dimensionality [N] and the provider has dimensionality [L][N][M] then each consumer element would map to [L][M] elements of the provider; and so on.
In the last two cases above, each consumer element maps to a two dimensional provider and so 2 arguments are required in order to specify a particular element. By default, the connection dimensionality (Dimension attribute) would be [N][M] and [L][M] respectively, for the last two cases above. As in the one dimensional case, the Dimension attribute could be set to '1', in which case only one connection would be created, and the access function arguments would be used to 'point' the connection at the required element.
In the example below, the default connection would mean that each element of the collector would connect to its reciprocal store element.
In the example below, the default connection would mean that each element of the collector (m,p) would connect to 'N' elements of the store.
In the most general case however, consumers are requesting events from trees of objects, and these can themselves be multidimensional.